const prefix = '[BLOCKER:';
const suffix = ':BLOCKER]';
const suffixReg = new RegExp(`${suffix}$`);
const { history } = window;

function BackBlocker() {
    this.map = {};
    this.popHandler = this.popHandler.bind(this);

    window.removeEventListener('popstate', this.popHandler);
    window.addEventListener('popstate', this.popHandler);
}

BackBlocker.prototype.addMap = function addMap(map) {
    this.map = map;
    console.log('[backblocker] addMap:', map);
};

/**
 * 监测 state 是否合法
 * @param {string} state 待检测的 state
 */
function isValidBlockerState(state) {
    if (!state) return false;
    if (typeof state !== 'string') return false;
    if (state.indexOf(suffix) !== -1) return true;
    return state.indexOf(prefix) === 0;
}

/**
 * 监测当前的 state 是否可以插入到历史记录
 * @param {string} stateName 状态名称
 */
function checkValid(stateName) {
    if (!stateName) return false;

    const currentState = history.state;
    if (!currentState) return true;
    if (typeof currentState !== 'string') return true;
    if (currentState.indexOf(prefix) === -1) return true;
    if (currentState.indexOf(stateName) === -1) return true;

    return false;
}

/**
 * 创建状态名
 * @param {string} stateName 待创建的状态名
 * @param {boolean} isEnd 是否结束状态
 */
function createState(stateName, isEnd = false) {
    if (!stateName) {
        throw new Error('state name should not be falsy');
    }

    const currentState = history.state;
    let res = `${prefix}|${stateName}`;
    if (isValidBlockerState(currentState)) {
        const currentStateWithoutSuffix = currentState.replace(suffixReg, '');
        res = `${currentStateWithoutSuffix}|${stateName}`;
    }

    if (isEnd) {
        res = `${res}${suffix}`;
    }

    return res;
}

/**
 * 添加用于拦截的历史状态
 * @param {string} stateName 状态名称
 */
BackBlocker.prototype.pushState = function pushState(stateName) {
    if (checkValid(stateName)) {
        const state = createState(stateName);
        const dumpState = createState(stateName, true);
        history.replaceState(state, null);
        history.pushState(dumpState, null);
    }
};

/**
 * 添加用于拦截的历史状态及其回调函数
 * @param {string} stateName 状态名称
 * @param {Function} handler 回调函数
 */
BackBlocker.prototype.pushStateHandler = function pushStateHandler(stateName, handler) {
    this.pushState(stateName);

    if (!this.map) {
        this.map = {};
    }
    
    this.map[stateName] = handler;
};

/**
 * 释放事件监听资源
 */
BackBlocker.prototype.dispose = function dispose() {
    window.removeEventListener('popstate', this.popHandler);
    this.map = null;
};

function getCurrentState(state) {
    if (typeof state !== 'string') return null;
    if (state.indexOf(prefix) !== 0) return null;
    const tokens = state.split('|');
    if (!tokens || tokens.length <= 0) return null;

    return tokens.pop();
}

BackBlocker.prototype.getHandler = function getHandler(state) {
    const currentState = getCurrentState(state);
    if (!currentState) return null;
    if (!this.map) return null;

    return this.map[currentState];
};

function isEndState(state) {
    if (!state) return false;
    if (typeof state !== 'string') return false;

    return suffixReg.test(state);
}

BackBlocker.prototype.popHandler = function popHandler() {
    const { state } = history;
    if (isEndState(state)) return;

    console.log('[backblocker] popHandler:', state);
    const handler = this.getHandler(state);
    if (!handler) return;

    handler();
};

export default BackBlocker;
